package services

import (
	"errors"
	"fmt"
	"hft/Database/admin"
	"hft/Http/Models/dao"
	"hft/Http/Models/request"
	"hft/Http/Models/response"
	utils "hft/Http/Utils"
	"hft/global"
	"hft/tools"
	"hft/tools/upload"
	"io"
	"mime/multipart"
	"regexp"
	"strings"
	"time"
)

type Upload struct{}

func (*Upload) UploadMultiFile(ossFilename string, PID int, claims tools.BaseClaims, fileMD5 string, fileName string, chunkTotal int, index int, file multipart.File, header multipart.FileHeader, fileType string, totalSize int) (data *response.FileRes, err error) {

	var account *admin.Account

	var rootDir *admin.FileGroup

	var nowDir *admin.FileGroup

	data, err = upload.OssAliyun.UploadMultiFile(fileMD5, ossFilename, index, chunkTotal, file, header.Size)
	if err != nil {
		return nil, err
	}
	// 如果上传完毕
	if data.ChunkTotal == data.Index {

		global.OC_DB.Scopes(dao.ParseAccountDao.Parse(claims, global.OC_DB)).First(&account)

		global.OC_DB.Model(&account).Association("Directory").Find(&rootDir)

		var link string

		if PID == 0 {
			PID = int(rootDir.ID)
			link = fmt.Sprintf("%v%v,", rootDir.Link, PID)
		} else {
			err = global.OC_DB.Where("id = ?", PID).First(&nowDir).Error

			if err != nil {
				return nil, errors.New("找不到该目录")
			}

			if rootDir.AccountId != int(account.ID) {
				return nil, errors.New("你无权修改该目录")
			}
			PID = int(nowDir.ID)
			link = fmt.Sprintf("%v%v,", nowDir.Link, PID)
		}

		global.OC_DB.Omit("id").Create(&admin.FileUploadAndDownload{
			Name:       fileName,
			Url:        data.ObjectName,
			ObjectName: data.ObjectName,
			Link:       link,
			Type:       fileType,
			Size:       totalSize,
			GroupId:    PID,
		})
	}

	return data, nil

}

func (*Upload) UploadFile(PID int, claims tools.BaseClaims, files []*multipart.FileHeader, ossFilename string) (fileRes *response.FileRes, err error) {

	var oss = upload.NewOss()

	var account *admin.Account

	var rootDir *admin.FileGroup

	var nowDir *admin.FileGroup

	var uploadFile *admin.FileUploadAndDownload

	global.OC_DB.Scopes(dao.ParseAccountDao.Parse(claims, global.OC_DB)).First(&account)

	global.OC_DB.Model(&account).Association("Directory").Find(&rootDir)

	var link string

	if PID == 0 {
		PID = int(rootDir.ID)
		link = fmt.Sprintf("%v%v,", rootDir.Link, PID)
	} else {
		err = global.OC_DB.Where("id = ?", PID).First(&nowDir).Error

		if err != nil {
			return nil, errors.New("找不到该目录")
		}

		if rootDir.AccountId != int(account.ID) {
			return nil, errors.New("你无权修改该目录")
		}
		PID = int(nowDir.ID)
		link = fmt.Sprintf("%v%v,", nowDir.Link, PID)
	}

	for _, file := range files {
		_, objectName, uploadErr := oss.UploadFile(file, ossFilename)
		if uploadErr != nil {
			panic(err)
		}
		var fileSplice = strings.Split(file.Filename, ".")
		uploadFile = &admin.FileUploadAndDownload{
			Name:       file.Filename,
			Url:        objectName,
			ObjectName: objectName,
			Type:       fileSplice[len(fileSplice)-1],
			Size:       int(file.Size),
			GroupId:    PID,
			Link:       link,
		}
		global.OC_DB.Omit("id").Create(&uploadFile)
	}

	data := &response.FileRes{FileName: uploadFile.Name, FilePath: uploadFile.Url, ChunkTotal: 1, Index: 1}

	return data, nil
}

// 获取用户的文件夹目录
func (*Upload) GetRoot(claims tools.BaseClaims) (dirs []*admin.FileGroup, err error) {

	var account *admin.Account

	var root *admin.FileGroup

	err = global.OC_DB.Where("username = ?", claims.Username).First(&account).Error

	if err != nil {
		return nil, errors.New("找不到账户信息")
	}

	global.OC_DB.Model(&account).Association("Directory").Find(&root)

	global.OC_DB.Where("link LIKE ?", fmt.Sprintf("%v%v,%%", root.Link, root.ID)).Find(&dirs)

	return utils.BuildDirForest(dirs), nil
}

// 添加目录

func (*Upload) CreateDir(dir *request.FileGroup, claims tools.BaseClaims) error {

	var account *admin.Account

	var rootDir *admin.FileGroup

	var parentDir *admin.FileGroup

	err := global.OC_DB.Scopes(dao.ParseAccountDao.Parse(claims, global.OC_DB)).First(&account).Error

	if err != nil {
		return errors.New("账号不存在")
	}

	if dir.PID == 0 {
		err = global.OC_DB.Model(&account).Association("Directory").Find(&rootDir)

		if err != nil {
			return errors.New("找不到账户根目录")
		}

		global.OC_DB.Create(&admin.FileGroup{Name: dir.Name, PID: int(rootDir.ID), AccountId: int(account.ID), Link: fmt.Sprintf("%v%v,", rootDir.Link, rootDir.ID)})

	} else {
		err = global.OC_DB.First(&parentDir, dir.PID).Error
		if err != nil {
			return errors.New("找不到该父目录")
		}

		if parentDir.AccountId != int(account.ID) {
			return errors.New("你无权修改该目录")
		}

		global.OC_DB.Create(&admin.FileGroup{Name: dir.Name, PID: dir.PID, AccountId: int(account.ID), Link: fmt.Sprintf("%v%v,", parentDir.Link, parentDir.ID)})
	}

	return nil
}

func (*Upload) EditDir(dir *request.FileGroup, claims tools.BaseClaims) (err error) {

	var account *admin.Account

	var nowDir *admin.FileGroup

	err = global.OC_DB.Scopes(dao.ParseAccountDao.Parse(claims, global.OC_DB)).First(&account).Error

	if err != nil {
		return errors.New("无该账号信息")
	}

	err = global.OC_DB.First(&nowDir, dir.PID).Error

	if err != nil {
		return errors.New("无该目录信息")
	}

	if nowDir.AccountId != int(account.ID) {
		return errors.New("你无权修改该目录")
	}

	global.OC_DB.Model(&nowDir).Update("name", dir.Name)

	return nil
}

func (*Upload) GetFiles(PID int, paginate *request.FilesListInfo, claims tools.BaseClaims) (data *utils.Page, err error) {
	var rootDir *admin.FileGroup
	var nowDir *admin.FileGroup
	var account *admin.Account
	var link string
	var files []*admin.FileUploadAndDownload

	err = global.OC_DB.Scopes(dao.ParseAccountDao.Parse(claims, global.OC_DB)).First(&account).Error

	if err != nil {
		return nil, errors.New("找不到该账号")
	}

	err = global.OC_DB.Model(&account).Association("Directory").Find(&rootDir)
	if err != nil {
		return nil, errors.New("找不到该目录")
	}

	if PID == 0 {
		PID = int(rootDir.ID)
		link = fmt.Sprintf("%v%v,%%", rootDir.Link, rootDir.ID)
	} else {
		err = global.OC_DB.First(&nowDir, PID).Error

		if err != nil {
			return nil, errors.New("找不到该目录")
		}

		match, _ := regexp.MatchString(fmt.Sprintf("^%v%v,", rootDir.Link, rootDir.ID), nowDir.Link)

		if !match {
			return nil, errors.New("你无权修改该目录")
		}

		link = fmt.Sprintf("%v%v,%%", nowDir.Link, nowDir.ID)

	}

	global.OC_DB.Scopes(dao.GetAccountDao.GetFileList(PID, link, paginate, global.OC_DB)).Find(&files).Limit(-1).Offset(-1).Count(&paginate.Total)

	paginate.Data = files

	return &paginate.Page, nil
}

func (*Upload) GetSingleFile(claims tools.BaseClaims, id int) (file *admin.FileUploadAndDownload, err error) {

	var account *admin.Account

	var fileGroup *admin.FileGroup

	if id == 0 {
		return nil, errors.New("未知错误500")
	}

	err = global.OC_DB.Where("username = ?", claims.Username).First(&account).Error

	if err != nil {
		return nil, errors.New("无该账号信息")
	}

	err = global.OC_DB.First(&file, id).Error

	if err != nil {
		return nil, errors.New("无该文件信息")
	}

	err = global.OC_DB.First(&fileGroup, file.GroupId).Error

	if err != nil {
		return nil, errors.New("你无权限获取该文件信息")
	}

	return file, nil
}

func (*Upload) UploadTempFile(claims tools.BaseClaims, file io.Reader, id int, filename string) (err error) {
	var beSetFile *admin.FileUploadAndDownload
	var fileGroup *admin.FileGroup
	var account *admin.Account

	err = global.OC_DB.First(&beSetFile, id).Error

	if err != nil {
		return errors.New("找不到需要被设置封面的文件")
	}

	err = global.OC_DB.First(&fileGroup, beSetFile.GroupId).Error

	if err != nil {
		return errors.New("未知错误500")
	}

	err = global.OC_DB.Scopes(dao.ParseAccountDao.Parse(claims, global.OC_DB)).First(&account).Error

	if err != nil {
		return errors.New("找不到账号信息")
	}

	if account.ID != uint(fileGroup.AccountId) {
		return errors.New("你无权设置改文件封面")
	}

	var bucket, _ = upload.NewBucket()

	err = bucket.DeleteObject(beSetFile.CoverOss) //删除原来的

	var nowDir = strings.Join(strings.Split(time.Now().Format("2006-01-02"), "-"), "")

	yunFileTmpPath := global.OC_CONFIG.AliyunOSS.BasePath + "/" + nowDir + "/" + filename

	err = bucket.PutObject(yunFileTmpPath, file)

	if err != nil {
		return errors.New("function formUploader.Put() Failed, err:" + err.Error())
	}

	global.OC_DB.Model(&beSetFile).Updates(map[string]interface{}{"cover_oss": yunFileTmpPath, "cover": "/" + yunFileTmpPath})

	return nil

}

func (*Upload) Delete(claims tools.BaseClaims, ids []int) (err error) {

	var account *admin.Account

	err = global.OC_DB.Scopes(dao.ParseAccountDao.Parse(claims, global.OC_DB)).Preload("Directory").First(&account).Error

	if err != nil {
		return errors.New("无该账号信息")
	}

	var files []*admin.FileUploadAndDownload

	err = global.OC_DB.Find(&files, ids).Error

	if err != nil {
		return errors.New("该文件不存在")
	}

	var dir *admin.FileGroup

	global.OC_DB.Where("p_id = ? AND account_id = ?", 1, account.ID).First(&dir)

	if !utils.IsBelongThisFileGroup(files, fmt.Sprintf("%v%v,", dir.Link, dir.ID)) {
		return errors.New("你无权删除该文件")
	}

	var objectNames []string

	for _, v := range files {
		objectNames = append(objectNames, v.ObjectName)
	}

	oss := upload.NewOss()

	err = oss.DeleteFile(objectNames)

	if err != nil {
		return errors.New("未知错误500")
	}

	err = global.OC_DB.Unscoped().Delete(&files).Error

	if err != nil {
		return errors.New("未知错误500")
	}

	return nil
}

var UploadService = new(Upload)
